#ifndef COMMON_NULL_ABLE_H_
#define COMMON_MULL_ABLE_H_
#include <cassert>

namespace fermat {

enum  NullType {
	KNullGenric = 0;
};
tempalte <typename T>
class NullAble {
public:
	/*!
	 * Creates an empty NullAble.
	 */
	NullAble():
		_value(),
		_isNull(true),
		_null(NullType::KNullGenric)
	{
	}

	NullAble(const NullType&):
		_value(),
		_isNull(true),
		_null(NullType::KNullGenric)
	{
	}

	/*!
	 * Creates a NullAble with the given value.
	 */
	NullAble(const T& value): 
		_value(value), 
		_isNull(false),
		_null(NullType::KNullGenric)
	{
	}
	/*!
	 * Creates a NullAble by copying another one.
	 */
	NullAble(const NullAble& other):
		_value(other._value),
		_isNull(other._isNull),
		_null(NullType::KNullGenric)
	{
	}

	/*!
	 * Destroys the NullAble.
	 */
	~NullAble()	
	{
	}

	/*!
	 * Assigns a value to the NullAble.
	 * @author lothar<liyinbin> 2017-01-05
	 * @param  value the value
	 * @return       self ref
	 */
	NullAble& assign(const T& value)
	{
		_value  = value;
		_isNull = false;
		return *this;
	}
	
	/*!
	 * Assigns another NullAble.
	 * @author lothar<liyinbin> 2017-01-05
	 * @param  other other object
	 * @return       self ref
	 */
	NullAble& assign(const NullAble& other)
		/// 
	{
		NullAble tmp(other);
		swap(tmp);
		return *this;
	}
	
	/*!
	 * set to null
	 * @author lothar<liyinbin> 2017-01-05
	 * @return          self ref
	 */
	NullAble& assign()
	{
		_isNull = true;
		return *this;
	}
	
	/*!
	 * Assigns a value to the NullAble.
	 */
	NullAble& operator = (const T& value)
	{
		return assign(value);
	}

	/*!
	 * Assigns another NullAble.
	 */
	NullAble& operator = (const NullAble& other)
	{
		return assign(other);
	}

	/*!
	 *  Assigns another NullAble.
	 */
	NullAble& operator = (int)
	{
		_isNull = true;
		return *this;
	}

	/*!
	 * Swaps this NullAble with other.
	 */
	void swap(NullAble& other)
	{
		std::swap(_value, other._value);
		std::swap(_isNull, other._isNull);
	}

	/*!
	 * 	Compares two NullAbles for equality
	 */
	bool operator == (const NullAble<T>& other) const
	{
		return (_isNull && other._isNull) || (_isNull == other._isNull && _value == other._value);
	}

	bool operator == (const T& value) const
		/// Compares NullAble with value for equality
	{
		return (!_isNull && _value == value);
	}

	bool operator == (const NullType&) const
		/// Compares NullAble with NullData for equality
	{
		return _isNull;
	}

	bool operator != (const T& value) const
		/// Compares NullAble with value for non equality
	{
		return !(*this == value);
	}

	bool operator != (const NullAble<T>& other) const
		/// Compares two NullAbles for non equality
	{
		return !(*this == other);
	}

	bool operator != (const NullType&) const
	{
		return !_isNull;
	}

	bool operator < (const NullAble<T>& other) const
	{
		if (_isNull && other._isNull) return false;

		if (!_isNull && !other._isNull)
			return (_value < other._value);

		if (_isNull && !other._isNull) return true;

		return false;
	}

	bool operator > (const NullAble<T>& other) const
	{
		return !(*this == other) && !(*this < other);
	}

	T& value()
	{
		if (!_isNull)
			return _value;
		else
			assert(false);
	}

	const T& value() const
	{
		if (!_isNull)
			return _value;
		else
			throw NullValueException();
	}

	const T& value(const T& deflt) const
	{
		return _isNull ? deflt : _value;
	}

	operator T& ()
	{
		return value();
	}

	operator const C& () const
	{
		return value();
	}

	bool isNull() const
	{
		return _isNull;
	}
	
	void clear()
	{
		_isNull = true;
	}
private:
	T         _value;
	bool      _isNull;
	NullType  _null;
};



template <typename T>
inline void swap(NullAble<T>& n1, NullAble<T>& n2)
{
	n1.swap(n2);
}


template <typename T>
std::ostream& operator<<(std::ostream& out, const NullAble<T>& obj) 
{
	if (!obj.isNull()) out << obj.value();
	return out;
}


template <typename T>
bool operator == (const NullType&, const NullAble<T>& n)
{
	return n.isNull();
}


template <typename T>
bool operator != (const T& c, const NullAble<T>& n)
{
	return !(n == c);
}


template <typename T>
bool operator == (const T& c, const NullAble<T>& n)
{
	return (n == c);
}


template <typename T>
bool operator != (const NullType&, const NullAble<T>& n)
{
	return !n.isNull();
}

}
#endif